在 Automation Test 中 Page Object Model (POM) 就是應用 OOP 設計出來的,所以需要先理解概念,後續做測試專案的時候才能運用自如。應用 OOP 設計再搭配之前 Module 和 Package 的概念,將會對你的專案架構設計產生很大的幫助。
說到物件導向,必須要知道的三個概念:
封裝 Encapsulation
上一篇文章講述的內容,把 attribute 和 Method 組成一個 Class,其實就是封裝的概念。
舉個應用例子,當需要處理多位學生的個人資料以及上課記錄等資料,而每位學生都有獨立的資料需要處理,因此把 學生的資料 和 處理資料的 method 封裝成一個 Class 如下:
class Student:
student_id = ""
student_name = ""
sex = ""
attendance = 0
def attend_lesson(self)
self.attendance += 1
透過這樣的設計,可以為每個學生建立一個 Object,而個別都擁有處理自己資料的方法。
繼承 Inheritance
從既有的 Class (父類別 Parent Class) 定義出新的 子類別 (Child Class),子類別可以繼承父類別的屬性和方法,亦可以加入自己的屬性和方法,甚至重新定義從父類別繼承的方法,但不影響父類別的方法。
如下的一個例子,寵物有很多種,但牠們都有進食技能。然而狗還可以抓貓,而貓則可以抓老鼠。這時候把他們都該有的屬性和方法寫進父類別,個別特有的方法寫在子類別。
class Pet:
# 每隻寵物,不管什麼類型,都有名字,因此初始化的動作在父類別進行
def __init__(self, name):
self.name = name
# 每隻寵物,不管什麼類型,都會吃東西
def eat(self):
print(f"{self.name} can eat")
# 定義寵物種類為狗
class Dog(Pet):
# 狗類寵物有抓貓技能
def catch_cat(self):
print(f"{self.name} can catch cat")
# 定義寵物種類為貓
class Cat(Pet):
# 貓類寵物有抓鼠技能
def catch_mouse(self):
print(f"{self.name} can catch mouse")
snoopy = Dog("Snoopy")
snoopy.eat()
snoopy.catch_cat()
garfield = Cat("Garfield")
garfield.eat()
garfield.catch_mouse()
Output:
Snoopy can eat
Snoopy can catch cat
Garfield can eat
Garfield can catch mouse
繼承的好處是可以提高方法的重用性,只需要在父類別撰寫一次,就可以被子類別重複使用。
除了這種一般的繼承,還有多重繼承和多層繼承。
多重繼承 : 同時繼承多過一個父類別,就像是同是繼承父親的基因,也繼承母親的基因。
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name} says Hello World!")
class Flyable:
def fly(self):
print(f"I can fly.")
class Bird(Animal, Flyable):
def sing(self):
print(f"{self.name} is singing.")
sparrow = Bird("Sparrow")
sparrow.speak()
sparrow.fly()
sparrow.sing()
Output:
Sparrow says Hello World!
I can fly.
Sparrow is singing.
多層繼承 : 子類別有父類別,父類別也有父類別,祖父的概念。子類別同樣可以得到祖父層的屬性與方法。
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name} like bone")
class Dog(Animal):
def speak(self):
print(f"{self.name}: Woof! Woof!")
class GoldenRetriever(Dog):
def fetch(self):
print(f"{self.name} is fetching a ball.")
dog = GoldenRetriever("Buddy")
dog.eat()
dog.speak()
dog.fetch()
Output:
Buddy like bone
Buddy: Woof! Woof!
Buddy is fetching a ball.
多型 Polymorphism
是指子類別繼承父類別的方法,但可能會有不一樣的處理方式。承上的例子,這些寵物都會發聲,但發出的聲音就不一樣了。
class Pet:
def make_sound(self):
print("Hello")
class Dog(Pet):
def make_sound(self):
print("Woof!")
class Cat(Pet):
def make_sound(self):
print("Meow!")
snoopy = Dog()
garfield = Cat()
# 呼叫通用方法,實際執行的方法取決於物件的類型
snoopy.make_sound() # 輸出: Woof!
garfield.make_sound() # 輸出: Meow!
順帶一題 Python 有內建的套件 abc
(abstract based class) ,有一個裝飾器 @abstractmethod
,用來標記 class 中的 method 為抽象方法,用處是父親沒有實際定義方法的內容,但其子類別必須定義該方法的實作內容,否則會噴錯,藉此來規範子類別需要實作的內容。
# 需 import abc 套件
from abc import abstractmethod, ABC
# Pet 需要繼承 ABC class 才能應用 @abstractmethod
class Pet(ABC):
# 標記為 abstractmethod,裡面沒有實作內容,會寫 pass
@abstractmethod
def make_sound(self):
pass
class Dog(Pet):
def make_sound(self):
print("Woof!")
class Cat(Pet):
# 沒有實作 make_sound() 的內容
def catch_mouse(self):
print("I can catch mouse")
snoopy = Dog()
snoopy.make_sound()
# 在 init 的時候就會因為沒有實作 make_sound() 而噴錯
garfield = Cat()
Output:
Woof!
...
...
TypeError: Can't instantiate abstract class Cat with abstract method make_sound
以上是關於 OOP 的介紹,需要理解這些概念,之後才會更好理解 Page Object Model 的設計,對於整個專案架構設計都很有幫助。